# -*- coding:utf-8 -*-
import time
import traceback

from pymouse import PyMouse
import os
import cv2
import crab
import argparse
from basic.logger import logger

from basic.windowOperate import cWindow

## 参数配置的主入口
class GameAssist:
    def __init__(self, wdname, args):
        """初始化"""
        cW = cWindow()
        # 取得窗口句柄
        cW.find_window_regex(wdname)
        cW.Maximize()
        cW.SetAsForegroundWindow()
        self.cW = cW

        # PyMouse对象，鼠标点击
        self.mouse = PyMouse()

        # 参数
        # 任务名称会映射到对应的图片配置文件夹
        self.dir = args.taskName
        # 最大尝试次数
        self.max = args.max
        # 任务重复次数
        self.repeat = args.times
        # 从步骤N开始
        self.index = args.index
        # 执行频率
        self.rate = args.rate
        # 执行模式
        self.mode = args.mode

    def find_button(self, target, template):
        """
        寻找target图片在template中的位置，返回应该点击的坐标。
        """
        theight, twidth = target.shape[:2]
        # 执行模板匹配，采用的匹配方式cv2.TM_SQDIFF_NORMED
        result = cv2.matchTemplate(target, template, cv2.TM_SQDIFF_NORMED)

        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
        # 如果匹配度小于99%，就认为没有找到。
        if min_val > 0.01:
            return None
        logger.debug("相似度" + str(min_val))
        # 绘制矩形边框，将匹配区域标注出来
        x = min_loc[0] + twidth // 3
        y = min_loc[1] + theight // 3
        return (x, y)

    def moveAndClick(self,pos,filename):
        self.mouse.move(pos[0], pos[1])
        time.sleep(0.5)
        self.mouse.press(pos[0], pos[1])
        time.sleep(self.rate)

    # 程序入口、控制中心_单次执行
    def startOnce(self, task_index, task_total):
        # 1、打开任务文件夹
        var_index = 0
        # 记录最大的节点值，如果轮询返回的坐标值小于最大坐标，则表明当前任务已经完成，且下一次任务已开启
        max_index = 0
        # 轮询次数
        polling_count = 1
        images = os.listdir("./images/task_" + self.dir)
        try:
            while var_index < len(images) and polling_count <= self.max and task_index <= task_total:  # listdir的参数是文件夹的路径
                filename = images.__getitem__(var_index)
                logger.info("[step-" + str(var_index + 1) + "]======================" + filename)

                # 等待撤退按钮消失，并进入下一个节点
                if filename.__contains__("delay_now"):
                    if self.waitToEnd(images[0]) == 'skip':
                        var_index += 2
                    else:
                        var_index = 1
                        task_index += 1
                    polling_count = 1
                    continue
                elif filename.__contains__("sleep_"):
                    time.sleep(float(filename[11:]))
                    continue

                # 2、先截取游戏区域大图，然后返回小图在大图中的坐标
                # 1、第一种截图方法，只能截取电脑主屏幕
                # self.screenshot()
                # 2、第二种截图方法，可以截取进程所在显示器的主屏幕
                start_XY = self.cW.grab_picture()
                src = cv2.imread('temp.png')
                target = cv2.imread('./images/task_' + self.dir + '/' + filename)
                # self.find_button(target,full_screen)
                pos = crab.find_position(target, src, start_XY[0], start_XY[1])

                if pos is None:
                    if filename.__contains__("once_") or filename.__contains__("_once"):
                        logger.info("没有找到该一次性按钮"+filename+"~即将跳过当前操作")
                        var_index += 1
                        continue
                    elif polling_count == self.max:
                        # 若最大次数尝试仍找不到且无撤退按钮，则启动轮询模式
                        self.mode = 'Polling'
                        # 启动轮询模式,并从当前节点开始向后执行
                        logger.info("第" + str(polling_count) + "次尝试点击，但是未找到按钮[" + filename + "]轮询模式启动……")
                        max_index = var_index

                        # 判断本次任务是不是已经结束
                        if self.get_position(images[0]):
                            logger.info("第" + str(task_index) + "次任务已执行完毕")
                            task_index += 1
                            continue

                        # 如果恰巧是找最后一个图片找不到，要考虑越界的问题
                        var_index = self.polling_start(var_index % len(images))
                        # 轮询如果找到的是更前面的节点，表明轮询前的那次任务可能已经结束了
                        if var_index <= max_index:
                            logger.info("第" + str(task_index) + "次任务已执行完毕")
                            task_index += 1
                        polling_count = 1
                        continue
                    else:
                        logger.info("第" + str(polling_count) + "次尝试点击，但是未找到按钮[" + filename + "]休息2s后继续……")
                        polling_count += 1
                    time.sleep(2)
                else:
                    if filename.__contains__("start_delay"):
                        self.moveAndClick(pos, filename)
                        if 'skip' == self.wait_to_retreat_btn():
                            var_index += 2
                        else:
                            var_index += 1
                        polling_count = 1
                        continue
                    logger.info("系统正在操作按钮：" + filename)
                    if self.mode == 'Polling':
                        self.mode = ''
                        logger.info("轮询模式已关闭")
                    # 移动鼠标并完成点击
                    self.moveAndClick(pos, filename)
                    # 指示当前执行的步骤序号
                    var_index = (var_index + 1) % len(images)
                    if var_index == 0:
                        return task_index
                    # 找到按钮后要对尝试次数进行初始化
                    else:
                        polling_count = 1
                        continue
            return task_index
        except:
            logger.error(traceback.format_exc())



    # 向后轮询模式，找到按钮后返回对应的步骤
    def polling_start(self, next_index):
        logger.info("系统已进入轮询模式~~")

        # 1、打开任务文件夹，读取图片列表
        images = os.listdir("./images/task_" + self.dir)
        # 1、打开任务文件夹，循环去找图片，找不到就一直循环
        while next_index < len(images):
            filename = images.__getitem__(next_index)
            logger.info("[polling-" + str(next_index + 1) + "]======================" + filename)

            # 1、第一种截图方法，只能截取电脑主屏幕
            # self.screenshot()
            # 2、第二种截图方法，可以截取进程所在显示器的主屏幕
            pos = self.get_position(filename)
            if pos is not None:
                logger.info("系统正在操作按钮：" + filename)
                if self.mode == 'Polling':
                    self.mode = ''
                    logger.info("轮询模式已关闭")
                self.moveAndClick(pos, filename)
                return (next_index + 1) % len(images)
            else:
                # 找不到按钮时向后查找
                next_index = (next_index + 1) % len(images)
                # 执行到最后一张图片仍未找到，则从头开始遍历
                logger.info("本次轮询未找到匹配的按钮")
                time.sleep(1)
                continue

    # 查找一遍退出、成功、失败按钮是否存在
    def find_retreat_or_common_click(self):
        start_XY = self.cW.grab_picture()
        src = cv2.imread('temp.png')
        common_images = os.listdir("./images/common")
        next_action = None
        for image in common_images:
            target = cv2.imread('./images/common/' + image)
            next_action = crab.find_position(target, src, start_XY[0], start_XY[1])
            if next_action:
                if image != 'retreat.png':
                    self.moveAndClick(next_action, image)
                    logger.info('"公共"按钮出现了，即将进入节点顺序模式')
                    # 公共按钮出现后就点击
                    return 'skip'
                else:
                    logger.info('"撤退"按钮出现了')
                    return 'wait'
            else:
                continue
        return next_action

    # 匹配并返回坐标
    def get_position(self, file_name):
        start_XY = self.cW.grab_picture()
        src = cv2.imread('temp.png')
        target = cv2.imread('./images/task_' + self.dir + '/' + file_name)
        # self.find_button(target,full_screen)
        pos = crab.find_position(target, src, start_XY[0], start_XY[1])
        return pos

    # 进入等待状态，直到退出按钮或结束按钮出现；使用这个方法可以有效减少频繁截屏导致的IO
    def wait_to_retreat_btn(self):
        has_retreat_btn = 'N'
        while has_retreat_btn == 'N':
            action = self.find_retreat_or_common_click()
            if action:
                # 找到退出按钮就退出
                return action
            else:
                logger.info("[任务执行中，系统正在等待“撤退”按钮出现,5s后再扫描一遍]")
                time.sleep(5)

    # 等待结束，当任务一直找不到按钮时，查看是否有退出按钮，如果有则等待一段时间
    def waitToEnd(self, first_image):
        has_retreat_btn = 'Y'
        while has_retreat_btn == 'Y':
            next_action = self.find_retreat_or_common_click()
            if next_action == 'skip':
                logger.info("[跳过下一个步骤]")
                return next_action
            else:
                if self.get_position(first_image) is None:
                    logger.info("[任务执行中，系统正在等待任务执行完毕]")
                    time.sleep(5)
                else:
                    logger.info("[系统检测到当前任务已结束，执行自动结束]")
                    return None

    # 程序入口、控制中心_允许多次执行
    def start(self):
        logger.info('3s后任务即将开始，请勿移动鼠标~')
        time.sleep(3)
        index = 1
        while index <= self.repeat:
            logger.info("即将开始第" + str(index) + "次" + self.dir + "任务执行")
            index = self.startOnce(index, self.repeat)
            logger.info("第" + str(index-1) + "次" + self.dir + "任务执行完毕~")
            index += 1
        logger.info("恭喜你，所有任务执行完毕~")

    # def start_drag(self):
    #     logger.info('3s后任务即将开始，请勿移动鼠标~')
    #     time.sleep(3)
    #     for



def config_task():
    # 接收全局参数
    parser = argparse.ArgumentParser(description='manual to this script')
    parser.add_argument('--taskName', type=str, default="survive")
    parser.add_argument('--times', type=int, default=1)
    parser.add_argument('--max', type=int, default=99)
    parser.add_argument('--index', type=int, default=0)
    parser.add_argument('--rate', type=float, default=1)  # 操作频率，定义操作时间间隔，默认为1s
    args = parser.parse_args()

    config = input("您想自定义任务执行配置吗,y/n?")
    if config == "y":
        task_name = input("请输入您接下来要做的任务名称,可选项：1、survive；2、fuben；"
                          "3、qiangzhe;4、竞技。请输入：")
        if task_name == "2":
            args.__setattr__("taskName", "fuben")
        elif task_name == "3":
            args.__setattr__("taskName", "qiangzhe")
        elif task_name == "4":
            args.__setattr__("taskName", "jingji")

        task_time = input("请输入该任务执行的次数：")
        args.__setattr__("time", int(task_time))
        task_index = input("请输入该任务开始执行的起始位置：")
        args.__setattr__("index", int(task_index))
        task_rate = input("请输入自动操作时间间隔，默认1s")
        args.__setattr__("rate", float(task_rate))
    logger.debug("配置结果为：" + str(args))
    return args


# 提取参数到类中
class Configuration:
    taskName = ''
    times = 0
    index = 0
    rate = 1.0
    max = 10  # 轮询最大尝试次数
    mode = ''  # Polling是轮询模式

    def __init__(self, task, times, index, rate, mode, max):
        self.taskName = task
        self.times = times
        self.index = index
        self.rate = rate
        self.mode = mode
        if max is not None:
            self.max = max


if __name__ == "__main__":
    while 1:
        # wdname 为连连看窗口的名称，必须写完整
        wdname = '火影忍者Online'

        # 配置任务
        args = config_task()
        game = GameAssist(wdname, args)
        logger.info("Start : %s" % time.ctime())
        time.sleep(1)
        game.start()
        logger.info("End : %s" % time.ctime())
        os.system("pause")
